<!--
  ~ Licensed to the Apache Software Foundation (ASF) under one or more
  ~ contributor license agreements.  See the NOTICE file distributed with
  ~ this work for additional information regarding copyright ownership.
  ~ The ASF licenses this file to You under the Apache License, Version 2.0
  ~ (the "License"); you may not use this file except in compliance with
  ~ the License.  You may obtain a copy of the License at
  ~
  ~   http://www.apache.org/licenses/LICENSE-2.0
  ~
  ~ Unless required by applicable law or agreed to in writing, software
  ~ distributed under the License is distributed on an "AS IS" BASIS,
  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  ~ See the License for the specific language governing permissions and
  ~ limitations under the License.
  -->


<template>
  <div
    v-show="node.visible"
    :class="nodeClasses"
    :fsType="fsType"
    class="we-tree-node"
  >
    <div
      :title="node.data.path"
      :style="contentStyle"
      class="we-tree-node__content"
      @contextmenu.prevent.stop="handleContextMenu"
      @click.stop="handleClick"
      @keyup.stop="handleKeyUp"
      @dblclick.stop="handleDblClick">
      <span v-if="expanded" class="fi-folder-o"/>
      <span v-else :style="'color: ' + supportIcon(node).color" :class="[ supportIcon(node).className, supportIcon(node).icon ]" />
      <template v-if="node.isEditState">
        <div
          :class="{'is-error': !inputValid}"
          class="we-tree-node__edit">
          <input
            ref="edit"
            :value="node.label"
            type="text"
            @click.stop
            @keyup.stop
            @blur="endNodeEdit"
            @keyup.enter.stop.prevent="endNodeEdit">
          <div
            v-if="errorMsg"
            class="we-tree-node__error">{{ errorMsg }}</div>
        </div>
      </template>
      <template v-else-if="node.data && node.data.isFn">
        <div class="we-tree-node__checkbox">
          <input
            v-model="node.data.load"
            :value="node.data.name"
            :disabled="node.data.disabled || (node.data.type==='self' && node.data.shared)"
            type="checkbox"
            @change="hanlderCheck">
          <view-modal :node="node.data">
            <span
              :title="node.data.name"
              :class="{expired: node.data.expire}">{{ node.data.name }}</span>
          </view-modal>
        </div>
      </template>
      <template v-else>
        <span class="we-tree-node__label">{{ node.label }}</span>
      </template>
    </div>
    <div
      v-show="expanded"
      class="we-tree-node__children">
      <we-tree-node
        v-for="(child, index) in node.computedNodes"
        :key="getNodeKey(child, index)"
        :node="child"
        :fs-type="fsType"
        :highlight-path="highlightPath"
        :currentNode="currentNode"/>
    </div>
  </div>
</template>
<script>
import mixin from './mixin.js';
import viewModal from './functionView';
import SUPPORTED_LANG_MODES from '@/common/config/scriptis.js';
export default {
  name: 'WeTreeNode',
  components: {
    viewModal,
  },
  mixins: [mixin],
  props: {
    node: {
      type: Object,
      default: () => {},
    },
    currentNode: {
      type: Object,
      defalut: {}
    }
  },
  data() {
    return {
      tree: null,
      expanded: false,
      inputValid: true,
      errorMsg: null,
      nameList: [],
      SUPPORTED_LANG_MODES
    };
  },
  computed: {
    isHasFileOpen() {
      if (!this.highlightPath) return false;
      const highlightList = this.highlightPath.split('/');
      // One-to-one correspondence between directories, all parent levels need to be recursively matched(目录一一对应,需递归匹配所有父层级)
      let flag = false;
      const checkName = (node) => {
        const name = node.data.name;
        const needToHighLighted = highlightList[node._level - 1];
        if (name === needToHighLighted) {
          if (node.parent) {
            checkName(node.parent);
          } else {
            flag = true;
          }
        }
      };
      checkName(this.node);
      return flag;
    },
    nodeClasses() {
      return {
        'is-expanded': this.expanded,
        'is-current': this.tree.store.currentNode === this.node,
        'is-actived': this.isHasFileOpen,
      };
    },
    contentStyle() {
      return {
        'padding-left': this.node._level * this.tree.indent + 'px',
      };
    },
  },
  watch: {
    'node.isEditState'(val) {
      if (val) {
        this.$nextTick(() => {
          this.$refs.edit && this.$refs.edit.focus();
          // set selected area(设置选中区域)
          // When the index is -1, it is a folder, and all will be selected by default(index为-1时，是文件夹，会默认选中全部)
          if (this.node.label) {
            const index = this.node.label.lastIndexOf('.');
            this.$refs.edit.setSelectionRange(0, index);
          }
        });
      }
    },
    'node.data.expanded'(val) {
      this.expanded = val;
    },
    'currentNode.isEditState'(val) {
      if (this.currentNode.data.path === this.node.data.path && val) {
        this.node.changeEditState(val);
      }
    }
  },
  created() {
    const parent = this.$parent;
    this.tree = parent.isTree ? parent : parent.tree;
    this.initData();
    this.initWatch();
  },
  methods: {
    initData() {
      this.node.isDirNull = true;
      let treeData = null;
      treeData = this.tree.data[0].children;
      if (treeData) {
        treeData.forEach((e) => {
          if (e.isLeaf) {
            this.nameList.push(e.name); // todo
          }
        });
      }
      // The root directory is opened by default during initialization(初始化的时候默认打开根目录)
      if (this.isRootDefaultOpen) {
        this.expanded = true;
      }
    },
    initWatch() {
      const nodeProps = this.tree.nodeProps || {};
      const propName = nodeProps.children || 'children';
      this.$watch(`node.data.${propName}`, () => {
        this.node.updateChildren();
      });
    },
    handleContextMenu(e) {
      const tree = this.tree;
      const store = tree.store;
      store.setCurrentNode(this.node);
      this.nameList = [];
      const nodeData = this.node.data;
      const childrenKey = tree.nodeProps.children || 'children';
      const that = this;
      if (nodeData && nodeData.children && nodeData.children.length) {
        nodeData.children.forEach((node) => {
          if (node.isLeaf) {
            this.nameList.push(node.name);
          }
        });
      } else if (tree && tree.loadDataFn && !nodeData.isLeaf) {
        tree.loadDataFn(this.node, (data) => {
          if (data) {
            that.$set(that.node.data, childrenKey, data);
            tree.store.filter();
          }
        });
      }
      this.tree.$emit('node-contextmenu', e, {
        nodeData,
        node: this.node,
        nameList: this.nameList,
      });
    },
    handleClick(e) {
      const store = this.tree.store;
      store.setCurrentNode(this.node);
      if (!this.node.isLeaf) {
        if (this.expanded) {
          this.expanded = false;
        } else {
          this.handleExpand();
        }
      }
      this.tree.$emit('node-click', e, {
        nodeData: this.node.data,
        node: this.node,
      });
    },
    handleExpand() {
      const tree = this.tree;
      const childrenKey = tree.nodeProps.children || 'children';
      const that = this;
      const children = that.node.data[childrenKey] || [];
      // If there is children data, do not request(如果有children数据就不去请求)
      if (tree && tree.loadDataFn && !children.length) {
        tree.loadDataFn(this.node, (data) => {
          if (data) {
            that.$set(that.node.data, childrenKey, data);
            this.$nextTick(() => {
              tree.store.filter();
            });
          }
          this.expanded = true;
        });
      } else {
        that.$set(that.node.data, childrenKey, children);
        this.expanded = true;
        tree.store.filter();
      }
    },
    handleKeyUp(e) {
      this.tree.$emit('node-keyup', e, {
        nodeData: this.node.data,
        node: this.node,
      });
    },
    handleDblClick(e) {
      if (this.node.isEditState) {
        this.endNodeEdit();
      } else {
        this.tree.$emit('node-dblclick', e, {
          nodeData: this.node.data,
          node: this.node,
        });
      }
    },
    endNodeEdit() {
      if (!this.node.isEditState) return;
      const oldLabel = this.node.label;
      const newLabel = this.$refs.edit.value;
      if (oldLabel === newLabel) {
        this.node.changeEditState(false);
        this.changeInputValid(true);
        this.errorMsg = '';
        return;
      }
      if (this.tree.nodeEditValid) {
        this.errorMsg = this.tree.nodeEditValid({
          label: newLabel,
          node: this.node.data,
        });
        // If the script type is sql or hql, it supports script modification suffix, and the modified suffix is ​​correct(如果脚本类型是sql或者是hql是支持脚本修改后缀的，且修改的后缀是正确的)
        const reg = /\.(hql|sql)$/i;
        const newResult = reg.test(newLabel);
        const oldResult = reg.test(oldLabel);
        if (oldResult) {
          if (newResult) {
            this.errorMsg = '';
          } else {
            this.errorMsg = '请填写正确后缀名';
          }
        }

        if (this.errorMsg) {
          this.node.changeEditState(true);
          this.changeInputValid(false);
          return;
        } else {
          this.node.changeEditState(false);
          this.changeInputValid(true);
          this.errorMsg = '';
        }
      }
      if (this.tree.beforeChange) {
        this.tree.beforeChange({
          label: newLabel,
          node: this.node.data,
        }, (isExist) => {
          if (!isExist) {
            this.node.changeEditState(true);
            this.changeInputValid(true);
          } else {
            this.changeInputValid(true);
            this.errorMsg = '';
            const evName = this.node.isNew ? 'node-create' : 'node-edit';
            this.node.isNew = false;
            this.node.changeEditState(false);
            this.node.label = newLabel;
            this.errorMsg = '';
            this.tree.$emit(evName, evName, {
              nodeData: this.node.data,
              node: this.node,
              oldLabel,
            });
          }
        });
      }
    },
    changeInputValid(valid) {
      this.inputValid = valid;
    },
    getNodeKey(node, index) {
      const nodeKey = this.tree.nodeKey;
      let key = index;
      if (!node.data) {
        return key;
      }
      if (nodeKey) {
        key = node.data[nodeKey];
      } else {
        key = node.data.name + index;
      }
      return key;
    },
    hanlderCheck(e) {
      this.tree.$emit('node-check', e, {
        nodeData: this.node.data,
        node: this.node,
      });
    },
    supportIcon(node) {
      const supportModes = this.SUPPORTED_LANG_MODES;
      const match = supportModes.find((item) => item.rule.test(this.node.label));
      if (node.isLeaf && match) {
        return {
          className: 'is-leaf',
          icon: match.logo,
          color: match.color
        }
      } else if (node.isLeaf && !match && !node.data.isFn) {
        return {
          className: 'is-leaf',
          icon: 'fi-file'
        }
      } else if (!node.isLeaf) {
        return {
          icon: 'fi-folder'
        }
      } else if (node.data.isFn) {
        return {
          className: 'is-checkbox',
        }
      }
    },
  },
};
</script>
